// RegAllocator.h
// A general registers allocator for all translators

#ifndef REGALLOCATOR_H
#define REGALLOCATOR_H

#include "crossbit/common.h"

namespace crossbit {

				enum RegAccessMode
				{
								USE = 0,
								DEF
				};

				class VBlock;

				class RegAllocator{
								public:
												// callback of regSpillIn and regSpillOut, provided for corresponding translators
												typedef void (* CBOfSpillIn) (XTMemAddr mem, XTRegNum treg);
												typedef void (* CBOfSpillOut)(XTRegNum treg, XTMemAddr mem);

												// reg_to_reg
												typedef void (* CBOfRegToReg) (XTRegNum reg1, XTRegNum reg2);
								public:
												// when different translator initialize the reg allocator, they should specify their own
												// callback pointers for the reg allocator
												RegAllocator( XTUint8 num_regs, CBOfSpillIn cb_spill_in, CBOfSpillOut cb_spill_out, CBOfRegToReg cb_regtoreg )
												{ 
																ra_num_of_reg = num_regs;
																ra_cb_spill_in = cb_spill_in;
																ra_cb_spill_out = cb_spill_out;
																ra_cb_reg_to_reg = cb_regtoreg;
																// initialize the vinst seq
																vinst_seq = 0;
																ra_spill_pool = (XTInt32 *)UTIL::XTMalloc(6 * ra_num_of_reg * sizeof(XTInt32));
																UTIL::XTMemset((void *)ra_spill_pool, 0, 6 * ra_num_of_reg * sizeof(XTInt32));
												}


												virtual ~RegAllocator()
												{
																if (ra_spill_pool)
																				UTIL::XTFree(ra_spill_pool);
												}

												virtual XTRegNum regAlloc(XTRegNum vreg, RegAccessMode mode) = 0;	        
												virtual XTRegNum regAllocForce(XTRegNum vreg, XTRegNum expect, RegAccessMode mode) = 0;
												virtual XTRegNum regAllocForceExcept(XTRegNum vreg, XTRegNum except, RegAccessMode mode) = 0;

												virtual void regAllocReserve(XTRegNum reg) = 0;
												virtual void regAllocRelease(XTRegNum reg) = 0;

												virtual void init(VBlock *vb) = 0;

												//for some trivial stuffs
												virtual void phaseTask()
												{}

												// In Reg allocator, we should maintain a vinst sequence to record the current VInst which are being encoding.
												virtual void incrementVinstSeq()
												{
																++vinst_seq;
												}

								protected:
												XTInt32 vinst_seq;
											  XTRegNum ra_num_of_reg;
												XTInt32 *ra_spill_pool;

												CBOfSpillIn ra_cb_spill_in;
												CBOfSpillOut ra_cb_spill_out;		
												CBOfRegToReg ra_cb_reg_to_reg;

												virtual void regSpillIn(XTRegNum vreg, XTRegNum treg)
												{
																(*ra_cb_spill_in)((XTMemAddr)(ra_spill_pool+vreg), treg);
												}

												// Spill out the allocated target reg for the vreg
												virtual XTRegNum regSpillOut(XTRegNum vreg) = 0;

												// ========================================
												// virtual registers status
												// ========================================
												const static XTInt32 UNMAPPED 		= 0x01;
												const static XTInt32 MAPPED 		= 0x02;
												// already mapped but have been spilled into memory
												const static XTInt32 SPILLED 		= 0x04;

												// ========================================
												// target register status
												// ========================================
												const static XTInt32 FREE			= 0x01;
												const static XTInt32 ALLOCATED		= 0x02;
												const static XTInt32 RESERVED		= 0x04; 

												// ========================================
												// this struct is used by both of the virtual
												// registers and target registers tables, to
												// record the regs' information which are now
												// under use.
												// ========================================
												struct RegUsage {
																XTInt32 status;
																XTRegNum mapped_to;		// mappted target register number
																XTUint32	inst;		// the num of the instruction belonged to
													};


				};

}

#endif
